#include "MainWindow.h"
#include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    init();//调用程序初始化函数,请勿在此方法前调用任何其他方法
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onReadyRead()
{
    analysisCmd(m_serialPort->readAll());
}

//程序初始化函数
void MainWindow::init()
{
    printMsg(ui->txtLog,"初始化程序...",MSG_TYPE::SYSTEM);

    this->setCentralWidget(ui->stackedWidget);//设置堆栈界面为主控件
    ui->stackedWidget->setCurrentIndex(0);//设置默认为pagMain为初始化界面
    this->showMaximized();//最大化窗口显示

    m_serialPort = new QSerialPort(this);//初始化串口实例
    updateSerialPortList();//初始化可用串口列表

    //加载配置文件
    if(!loadConfig(g_configConfigFilePath))printMsg(ui->txtLog,"未找到配置文件.",MSG_TYPE::FALSE);

    //绑定信号槽
    connect(m_serialPort,SIGNAL(readyRead()),this,SLOT(onReadyRead()));

    printMsg(ui->txtLog,"程序初始化完成!",MSG_TYPE::SYSTEM);
}


//通过界面信息设置串口参数
void MainWindow::setSerialByUiInfo()
{
    if(m_serialPort->isOpen()){//如果串口已经打开,则拒绝设置串口参数
        printMsg(ui->txtLog,"请关闭串口后再设置串口连接参数.",MSG_TYPE::FALSE);
        return;
    }

    m_serialPort->setPortName(ui->combSerialPort->currentText());//设置串口名称
    m_serialPort->setBaudRate(ui->combBaudrRate->currentText().toUInt());//设置波特率

    //设置数据位
    int indexData = ui->combDataBits->currentIndex();
    if(indexData == 0){//8位数据位
        m_serialPort->setDataBits(QSerialPort::Data8);
    }else if(indexData == 1){//7位数据位
        m_serialPort->setDataBits(QSerialPort::Data7);
    }else if(indexData == 2){//6位数据位
        m_serialPort->setDataBits(QSerialPort::Data6);
    }else if(indexData == 3){//5位数据位
        m_serialPort->setDataBits(QSerialPort::Data5);
    }

    //设置校验位
    int indexParity = ui->combParityBit->currentIndex();
    if(indexParity == 0){//无校验
        m_serialPort->setParity(QSerialPort::NoParity);
    }else if(indexParity == 1){//奇校验
        m_serialPort->setParity(QSerialPort::OddParity);
    }else if(indexParity == 2){//偶校验
        m_serialPort->setParity(QSerialPort::EvenParity);
    }else if(indexParity == 3){//0校验
        m_serialPort->setParity(QSerialPort::SpaceParity);
    }else if(indexParity == 4){//1校验
        m_serialPort->setParity(QSerialPort::MarkParity);
    }

    //设置停止位
    int indexStop = ui->combStopBit->currentIndex();
    if(indexStop == 0){//1位停止位
        m_serialPort->setStopBits(QSerialPort::OneStop);
    }else if(indexStop == 1){//1.5位停止位
        m_serialPort->setStopBits(QSerialPort::OneAndHalfStop);
    }else if(indexStop == 2){//2位停止位
        m_serialPort->setStopBits(QSerialPort::TwoStop);
    }

    //设置流控
    int indexFluid = ui->combFluidControl->currentIndex();
    if(indexFluid == 0){//无流控
        m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
    }else if(indexFluid == 1){//软流控
        m_serialPort->setFlowControl(QSerialPort::SoftwareControl);
    }else if(indexFluid == 2){//硬流控
        m_serialPort->setFlowControl(QSerialPort::HardwareControl);
    }
}

//打印日志信息,第一个参数是文本对象,第二个参数是文本信息,第三个参数是消息类型
void MainWindow::printMsg(QTextBrowser *obj, QString msg, MSG_TYPE type)
{
    QString resultStr;
    resultStr += getCurrentTiem()+msg;

    //设置文本颜色
    if(type == MSG_TYPE::SYSTEM){//打印系统消息
        obj->setTextColor("black");
    }else if(type == MSG_TYPE::SUCCESS){//打印操作成功消息
        obj->setTextColor("green");
    }else if(type == MSG_TYPE::FALSE){//打印操作失败消息
        obj->setTextColor("red");
    }

    //打印消息
    obj->append(resultStr);

    obj->setTextColor("black");
}

//获取当前时间字符串,显示格式为 分分:秒秒
QString MainWindow::getCurrentTiem()
{
    QString temp;
    temp.append("[");
    temp.append(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss"));
    temp.append("]");
    return temp;
}

//更新可用串口列表
void MainWindow::updateSerialPortList()
{
    printMsg(ui->txtLog,"正在刷新串口列表...",MSG_TYPE::SYSTEM);

    ui->combSerialPort->clear();//清除原有的窗口列表

    QList<QSerialPortInfo>  serialPorts = QSerialPortInfo::availablePorts();//获取当前可用窗口列表信息
    for(QSerialPortInfo& info : serialPorts){//在界面中加入串口信息
        ui->combSerialPort->addItem(info.portName());

    }

    printMsg(ui->txtLog,"串口列表刷新完成.",MSG_TYPE::SUCCESS);
}

//加载配置文件
bool MainWindow::loadConfig(QString filePath)
{
    QFile file(filePath);
    if(!file.exists())return false;//如果文件不存在则返回false

    QSettings setting(filePath,QSettings::IniFormat);
    setting.setIniCodec("UTF-8");

    //串口设置部分
    int index;
    index=ui->combSerialPort->findText(setting.value("serialPort/name").toString());
    if(index!=-1)ui->combSerialPort->setCurrentIndex(index);

    index=ui->combBaudrRate->findText(setting.value("serialPort/baudRate").toString());
    if(index!=-1)ui->combBaudrRate->setCurrentIndex(index);

    index=setting.value("serialPort/dataBits").toInt();
    ui->combDataBits->setCurrentIndex(index);

    index=setting.value("serialPort/parityBits").toInt();
    ui->combParityBit->setCurrentIndex(index);

    index=setting.value("serialPort/stopBits").toInt();
    ui->combStopBit->setCurrentIndex(index);

    index=setting.value("serialPort/fluidControl").toInt();
    ui->combFluidControl->setCurrentIndex(index);

    ui->editPswd->setText(setting.value("serialPort/pswd").toString());
    return true;
}

//保存配置文件
void MainWindow::saveConfig(QString filePath)
{
    QSettings setting(filePath,QSettings::IniFormat);
    setting.setIniCodec("UTF-8");

    //服务器部分
    setting.setValue("serialPort/name",ui->combSerialPort->currentText());
    setting.setValue("serialPort/baudRate",ui->combBaudrRate->currentText());
    setting.setValue("serialPort/dataBits",ui->combDataBits->currentIndex());
    setting.setValue("serialPort/parityBits",ui->combParityBit->currentIndex());
    setting.setValue("serialPort/stopBits",ui->combStopBit->currentIndex());
    setting.setValue("serialPort/fluidControl",ui->combFluidControl->currentIndex());
    setting.setValue("serialPort/pswd",ui->editPswd->text());
}

//解析命令
void MainWindow::analysisCmd(QByteArray recData)
{
    printMsg(ui->txtLog,"<-"+recData.toHex(' ').toUpper(),MSG_TYPE::SYSTEM);
}

//设置ui界面的串口连接参数的comb是否可用
//如果参数为真,则可切换.否则不可切换
void MainWindow::setSerialSettingEnable(bool enable)
{
    //设置串口参数是否能修改
    ui->combSerialPort->setEnabled(enable);
    ui->btnUpdateSerialPort->setEnabled(enable);
    ui->combBaudrRate->setEnabled(enable);
    ui->combDataBits->setEnabled(enable);
    ui->combParityBit->setEnabled(enable);
    ui->combStopBit->setEnabled(enable);
    ui->combFluidControl->setEnabled(enable);
}

unsigned char MainWindow::crc8(QByteArray arr, int len)
{
    static const unsigned int crc8Table[256] =
        {
            0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
            0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
            0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
            0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
            0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
            0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
            0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
            0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
            0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
            0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
            0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
            0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
            0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
            0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
            0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
            0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
        };

    unsigned char crc8 = 0;

    auto data=arr.begin();
    data++;
    len--;
    while (len--)
    {
        crc8 = crc8 ^ (*data++);
        crc8 = crc8Table[crc8];
    }

    return crc8;
}


//重写程序关闭函数
void MainWindow::closeEvent(QCloseEvent *e)
{
    saveConfig(g_configConfigFilePath);//关闭程序前保存配置
    e->accept();
}

void MainWindow::on_btnUpdateSerialPort_clicked()
{
    updateSerialPortList();
}


void MainWindow::on_btnConnectSerialPort_clicked()
{
    //打开串口
    if(!m_serialPort->isOpen()){
        setSerialByUiInfo();//设置串口参数
        if(m_serialPort->open(QIODevice::ReadWrite)){//如果打开串口成功
            setSerialSettingEnable(false);
            ui->btnConnectSerialPort->setIcon(QIcon(":/imgs/connectBtn/connected.png"));
            ui->btnConnectSerialPort->setText("已连接");

            printMsg(ui->txtLog,"串口打开成功!",MSG_TYPE::SUCCESS);
        }else{//串口打开失败
            printMsg(ui->txtLog,"串口打开失败.",MSG_TYPE::FALSE);
        }
    }else{//如果串口已经打开则关闭串口
        ui->btnConnectSerialPort->setIcon(QIcon(":/imgs/connectBtn/disconnected.png"));
        ui->btnConnectSerialPort->setText("已关闭");
        setSerialSettingEnable(true);
        m_serialPort->close();

        printMsg(ui->txtLog,"串口已关闭.",MSG_TYPE::SYSTEM);
    }
}


void MainWindow::on_btnToCheckState_clicked()
{
    if(!m_serialPort->isOpen())return;
    if(ui->editPswd->text().count()!=6){
        printMsg(ui->txtLog,"密码长度不正确.",MSG_TYPE::FALSE);
        return;
    }

    QByteArray arr;
    arr.resize(9);
    arr[0]=0xee;
    arr[1]=0x00;
    arr[2]=0x08;
    arr[3]=0x01;
    arr[4]=0xff;
    arr[5]=0x02;

    //密码
    arr[6]=ui->editPswd->text().mid(0,2).toUInt();
    arr[7]=ui->editPswd->text().mid(2,2).toUInt();
    arr[8]=ui->editPswd->text().mid(4,2).toUInt();
    arr.append(crc8(arr,9));

    m_serialPort->write(arr);
    printMsg(ui->txtLog,"->"+arr.toHex(' ').toUpper(),MSG_TYPE::SYSTEM);
}


void MainWindow::on_btnChanggePswd_clicked()
{
    if(!m_serialPort->isOpen())return;
}


void MainWindow::on_btnToUserState_clicked()
{
    if(!m_serialPort->isOpen())return;
    if(ui->editPswd->text().count()!=6){
        printMsg(ui->txtLog,"密码长度不正确.",MSG_TYPE::FALSE);
        return;
    }

    QByteArray arr;
    arr.resize(9);
    arr[0]=0xee;
    arr[1]=0x00;
    arr[2]=0x08;
    arr[3]=0x01;
    arr[4]=0xff;
    arr[5]=0x01;

    //密码
    arr[6]=ui->editPswd->text().mid(0,2).toUInt();
    arr[7]=ui->editPswd->text().mid(2,2).toUInt();
    arr[8]=ui->editPswd->text().mid(4,2).toUInt();
    arr.append(crc8(arr,9));

    m_serialPort->write(arr);
    printMsg(ui->txtLog,"->"+arr.toHex(' ').toUpper(),MSG_TYPE::SYSTEM);
}

void MainWindow::on_btnConfirmPswd_clicked()
{
    if(!m_serialPort->isOpen())return;
    if(ui->editPswd->text().count()!=6){
        printMsg(ui->txtLog,"密码长度不正确.",MSG_TYPE::FALSE);
        return;
    }

    QByteArray arr;
    arr.resize(9);
    arr[0]=0xee;
    arr[1]=0x00;
    arr[2]=0x08;
    arr[3]=0x01;
    arr[4]=0xff;
    arr[5]=0x04;

    //密码
    arr[6]=ui->editPswd->text().mid(0,2).toUInt();
    arr[7]=ui->editPswd->text().mid(2,2).toUInt();
    arr[8]=ui->editPswd->text().mid(4,2).toUInt();
    arr.append(crc8(arr,9));

    m_serialPort->write(arr);
    printMsg(ui->txtLog,"->"+arr.toHex(' ').toUpper(),MSG_TYPE::SYSTEM);
}


void MainWindow::on_btnChangePswd_clicked()
{
    if(!m_serialPort->isOpen())return;
    if(ui->editNewPswd->text().count()!=6){
        printMsg(ui->txtLog,"新密码长度不正确.",MSG_TYPE::FALSE);
        return;
    }

    QByteArray arr;
    arr.resize(9);
    arr[0]=0xee;
    arr[1]=0x00;
    arr[2]=0x08;
    arr[3]=0x01;
    arr[4]=0xff;
    arr[5]=0x05;

    //密码
    arr[6]=ui->editNewPswd->text().mid(0,2).toUInt();
    arr[7]=ui->editNewPswd->text().mid(2,2).toUInt();
    arr[8]=ui->editNewPswd->text().mid(4,2).toUInt();
    arr.append(crc8(arr,9));

    m_serialPort->write(arr);
    printMsg(ui->txtLog,"->"+arr.toHex(' ').toUpper(),MSG_TYPE::SYSTEM);
}

